package com.cskaoyan.javase.oop2._2polymorphic._2advantage;

/**
 * @description: 多态的优缺点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

import javafx.animation.Animation;

/**
 * > 引例
 * - 科学家要收集动物的叫声去研究
 * - 定义猫，狗实际动物类，它们都会叫
 * - 定义收集猫、狗叫声的方法
 * - 要收集猪的声音，怎么办呢
 *
 *
 * 收集每种动物的叫声如果都重新写一个方法,过于复杂了,能不能一个方法把所有动物的叫声都研究了呢?
 * 可以,将父类作为方法的形参类型,这样方法就可以传入不同的子类对象了,
 *      发生多态现象,具体调用方法时,根据对象的具体类型来决定行为
 *
 * 多态的优点:
 *      1.- 要实现多态，必须要继承，提高了程序的可维护性（继承保证）
 * -    2.发生多态后，同一个引用调用方法产生不同的行为
 *   -      提高了程序的简洁性和扩展性（多态保证）
 *
 * 多态的缺点:
 *      父类引用会限制方法的访问范围,子类独有的方法是无法用父类引用访问的
 *      如果做强转,稍有不慎会报错,导致程序终止
 *
 * 新需求:
 *  科学家已经不满足于研究普通动物了,开始研究人类了,但是人类比较特殊,人叫过来配合研究得加钱
 *  所以人有独特的行为: 加钱
 *  人必须先加钱,才能叫
 *
 *  这时候,父类引用就无法访问子类独有的方法了,就无法完成调用加钱的方法,那怎么办呢?
 * 这是引用是父类的引用,它限制了成员的访问范围,只需要把父类的引用转换成子类引用就不会再受这个限制了
 * 这里存在类型转换,父类 --> 子类
 * 它属于强制类型转换,语法: (子类的类名) 父类的引用
 *
 * 引用数据类型的强制类型转换:
 *      1.发生的前提: 必须将父类引用强转成它的子类类型的引用,如果不是子类,会编译报错
 *      2.成功的前提: 强转后的子类类型必须是父类引用指向的子类对象的真实类型
 *          Animal ---> Person
 *          Person ---> Person
 *      3.引用数据类型的强制类型转换,或者叫"向下转型",它是很危险的,一旦强转失败,JVM会抛出ClassCastException来终止程序执行(强转后的子类类型不是父类引用指向的子类对象的真实类型)所以引用数据类型做强转一定要慎重考虑,不是乱玩的
 *      4.Java提供了检测手段,可以检测父类引用指向的子类对象到底是什么类型,从而帮助我们正确的完成强制类型转换,使用关键字instanceof
 *          语法: 引用名 instanceof 类名
 *      该语法会返回一个布尔类型的值,用来指示引用所指向的对象是否是后面类名的对象或者子类对象
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        //collectCatVoice(new Cat());
        collectAnimalVoice(new Cat());
        collectAnimalVoice(new Dog());
        collectAnimalVoice(new Pig());

        collectAnimalVoice(new Person());

        //Person p = new Cat();
    }

    /*//收集猫叫声的方法,搞一只猫过来
    public static void collectCatVoice(Cat c){
        //抓过来,叫
        c.shout();
        //收集研究
    }*/

    //收集动物的叫声,该方法使用父类Animal作为形参的数据类型,这样该方法可以传入Animal对象,也可以传入它的子类对象
    public static void collectAnimalVoice(Animal a) {
        //做if判断,只有当a指向Person对象时,才做强转
        //将Animal a引用强转成Person引用
        if (a instanceof Person) {
            //进入if表示a指向的就是Person对象,做强转
            Person p = (Person) a;
            p.addMoney();
        }
        a.shout();
    }

}

class Animal {
    int age;
    String name;

    public void shout() {
        System.out.println("动物叫");
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵喵");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪汪");
    }
}

class Pig extends Animal {
    @Override
    public void shout() {
        System.out.println("哼哼哼哼");
    }
}

class Person extends Animal {
    @Override
    public void shout() {
        System.out.println("嘤嘤嘤嘤");
    }

    //加钱是子类独有的方法
    public void addMoney() {
        System.out.println("给钱了就叫!");
    }
}